/*
 * I got the basis of this code from Daniel Sobral at
 * http://dcsobral.blogspot.com/2009/07/getting-around-type-erasure-with.html.
 * He does not make the license clear.  However, unless otherwise prohibited
 * I'm going to make my version LGPLv3.  -- Joshua Gooding
 */

package org.skavookie.expressions

import reflect.Manifest

/**
 * Created by IntelliJ IDEA.
 * User: joshua
 * Date: 5/12/11
 * Time: 8:22 AM
 * To change this template use File | Settings | File Templates.
 */

trait Registry {
	def register[T](name: Any, item: T)(implicit m: Manifest[T]): Option[T]
	def get[T](key: Any)(implicit m: Manifest[T]): Option[T]
}

object Registry {

	def apply(default: (Manifest[_], Any) => Option[Any]): Registry =
		new Registry.Default(default)
	def apply(dmap: Map[(Manifest[_], Any), Option[Any]]): Registry =
		apply((m: Manifest[_], key: Any) => dmap((m,key)))
	def apply(): Registry = apply(defaultDefault _)

	class Default(private val default: (Manifest[_], Any) => Option[Any]) extends Registry {

		private val _map = scala.collection.mutable.Map.empty[Any, (Manifest[_], Any)]

		def register[T](key: Any, item: T)(implicit m: Manifest[T]): Option[T] = {
			val previous = get[T](key)(m)
			_map(key) = (m, item)
			previous
		}

		def get[T](key: Any)(implicit m: Manifest[T]): Option[T] = {
			val o = _map.get(key)

			(o match {
				case Some((om: Manifest[_], s: Any)) =>
					if (om <:< m) Some(s.asInstanceOf[T]) else None
				case _ => None
			}) match {
				case None => _getDefault[T](m, key)
				case s => s
			}
		}

		private def _getDefault[T](m: Manifest[T], key: Any) = default(m, key) match {
			case Some((_, s: Any)) => Some(s.asInstanceOf[T])
			case _ => None
		}
	}

	type ManAny = (Manifest[_], Any)
	def defaultDefault(m: Manifest[_], key: Any): Option[_] = None

}